/** @file log.hpp Log output to use */
#pragma once

#include <fstream>

#include "util.hpp"

/** A logger
 * There are two types of logger output, the one used during rendering and the one used during testing */
class Log
{
public:

  /** Write outuput to the log
   * @param o output string */
  virtual void writeOut(const std::string& o) =0;
};

/** A file log */
class FileLog: public Log
{
protected:

  /** The file object to output to */
  std::ofstream f;

public:

  /** Construct
   * @param fname filename to output */
  FileLog(const std::string& fname);

  /** Destroy
   * This will close the file */
  ~FileLog();

  void writeOut(const std::string& m);
};

/** A terminal logger */
class TermLog: public Log
{
public:

  void writeOut(const std::string& m);
};

/** A meta-logger
 * This will configure itself based on whether we are testing or not */
class MetaLog: public Log
{
protected:

  std::unique_ptr<FileLog> flog;
  std::unique_ptr<TermLog> tlog;
  //std::unique_ptr<GuiLog> glog;

public:

  /** Construct
   * If testing, it will use flog and tlog, if rendering it will use flog, tlog, and glog */
  MetaLog();

  /** Destroy */
  ~MetaLog();

  void writeOut(const std::string& m);
};

/** Write output to a log
 * @param out log to output to
 * @param data data to write */
template <typename T> inline Log* operator<<(Log* out, const T& data)
{
  out->writeOut(asString<T>(data));
  return out;
}
//template <typename T> inline std::shared_ptr<Log> operator<<(std::shared_ptr<Log> out, const T& data)
//{
//  out.get() << data;
//}
template <typename T> inline std::unique_ptr<Log> operator<<(std::unique_ptr<Log> out, const T& data)
{
  out.get() << data;
}
